#pragma once
#include "utils.h"
#include <Windows.h>
#include <unordered_map>

struct Game {
  uint32 get_taxi_node_id(uint32 index);
  uint32 get_num_taxi_nodes();
  std::string get_taxi_node_name_ex(uint32 node_id);
  // FIXME: 有bug, 用另一个
  std::string get_taxi_node_name(uint32 node_id);
  void take_taxi(uint32 index);
  /**
   * @brief 销毁物品
   * @param bag_index 背包索引 [0, 4]; 0 是主背包; 1-4 是背包, 从右到左.
   * @param slot 物品槽; 从 0 开始. 主背包需要+0x23;
   */
  void destroy(uint8 bag_index, uint8 slot);
  void sell(uint64 npc_id1, uint64 npc_id2, uint64 item_id1, uint64 item_id2);
  void equip(uint8 bag_index, uint8 container_slot, uint8 equip_slot);
  void send_mail(uint64 mailbox, const std::string &receiver,
                 const std::string &subject, const std::string &content,
                 const std::vector<uint64> items, const uint32 gold);
  void select(uint64 id1, uint64 id2, uint32 flag = 1);
  void macro(const std::string &content);
  void click(float x, float y, float z, uint32 flag = 1);

  std::tuple<uint32, uint32, uint8> get_spell_cooldown(uint32 spell_id);
  std::string get_spell_name_ex(uint32 spell_id);
  std::string get_spell_name(uint32 spell_id);
  std::string get_item_subtype(uint32 type_index, uint32 subtype_index);
  uint32 get_item_subtype_index(uint32 item_id, uint32 edxv = 1,
                                uint32 r8dv = 0) const;
  std::string get_item_type(uint32 index, uint32 r8dv = 0) const;
  uint32 get_item_type_index(uint32 item_id, uint32 edxv = 0,
                             uint32 r8dv = 0) const;
  uint64 get_item_type_arr(uint32 item_id) const;
  uint32 get_time();
  void key_down(uint32 code);
  void key_up(uint32 code);
  uint64 get_object_index(uint64 id1, uint64 id2);
  uint64 get_object(uint64 id1, uint64 id2);
  uint64 get_object(uint64 index);
  std::pair<uint64, uint64> get_id(uint64 ptr);
  uint64 get_gs58();
  uint64 get_gs58_local();
  // --- send_call ---
  int64 send_call(uint64 *args);
  // --- Hook Main Thread ---
  void hook_main_thread();
  void unhook_main_thread();

  // --- Constructors ---
  Game() = delete;
  Game(uint32 pid, HWND window, uint64 base);
  Game(Game &&) = default;
  Game(const Game &) = default;
  Game &operator=(Game &&) = default;
  Game &operator=(const Game &) = default;
  ~Game();

  uint64 core_base();
  void set_core_base(uint64 core_base);

private:
  static std::unordered_map<uint32, std::string> spell_names_;
  static std::unordered_map<uint32, uint64> item_type_arr_map_;
  static uint64 core_base_;

private:
  uint32 pid_;
  HWND window_; // 游戏窗口句柄
  uint64 base_; // 游戏模块基址
};
